#include "Common.h"

#include "App_Files.h"
#include "BspGpioAlt.h"

#include <unistd.h>
#include <fcntl.h>

#define BSP_GPIO_DIRECT_STRING_IN       "in"
#define BSP_GPIO_DIRECT_STRING_OUT      "out"
#define BSP_GPIO_DIRECT_STRING_HIGH     "high"
#define BSP_GPIO_DIRECT_STRING_LOW      "low"

static CHAR gszDirection[][32] = 
{
    [BSP_GPIO_DIRECTION_IN] = BSP_GPIO_DIRECT_STRING_IN,
    [BSP_GPIO_DIRECTION_OUT] = BSP_GPIO_DIRECT_STRING_OUT,
    [BSP_GPIO_DIRECTION_OUT_LOW] = BSP_GPIO_DIRECT_STRING_LOW,
    [BSP_GPIO_DIRECTION_OUT_HIGH] = BSP_GPIO_DIRECT_STRING_HIGH,
};

/**********************************************************
 * Function Name:        BspGpio_SetGpioExport
 * Description:          导出指定编号的GPIO引脚，使其可通过sysfs接口进行操作
 * Parameters[in]:       IN UINT32 gpio
 * Parameters[out]:      None
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.13
 **********************************************************/
ULONG BspGpio_SetGpioExport(IN UINT32 gpio)
{
    CHAR buf[128] = {0};
    ULONG uRet = 0;

	snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d", gpio);
	if(access(buf, F_OK) != 0)
	{
		snprintf(buf, sizeof(buf), "/sys/class/gpio/export");
        uRet = AppFile_writeInt32(buf, gpio);
	}

	return uRet;
}

/**********************************************************
 * Function Name:        BspGpio_SetGpioUnexport
 * Description:          取消导出的GPIO编号
 * Parameters[in]:       IN UINT32 gpio
 * Parameters[out]:      None
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.13
 **********************************************************/
ULONG BspGpio_SetGpioUnexport(IN UINT32 gpio)
{
    CHAR buf[128] = {0};
    ULONG uRet = 0;

	snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d", gpio);
	if(access(buf, F_OK) == 0)
	{
		snprintf(buf, sizeof(buf), "/sys/class/gpio/unexport");
        uRet = AppFile_writeInt32(buf, gpio);
	}

	return uRet;
}

/**********************************************************
 * Function Name:        BspGpio_SetGpioDirect
 * Description:          设置管脚方向
 * Parameters[in]:       IN UINT32 gpio
 *                       IN BSP_GPIO_DIRECTION_e enDirect
 * Parameters[out]:      None
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.13
 **********************************************************/
ULONG BspGpio_SetGpioDirect(IN UINT32 gpio, IN BSP_GPIO_DIRECTION_e enDirect)
{
    CHAR buf[64] = {0};
    ULONG uRet = 0;

    if(enDirect >= BSP_GPIO_DIRECTION_MAX)
    {
        uRet = STAT_ERR_INVAILD_PARAM;
        return uRet;
    }

	sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio);
    if(access(buf, F_OK) == 0)
    {
        uRet = AppFile_writeStr(buf, gszDirection[enDirect]);
    }

	return uRet;
}

/**********************************************************
 * Function Name:        BspGpio_GetGpioDirectByString
 * Description:          根据direct文件内容，转换成枚举
 * Parameters[in]:       IN CHAR *pcStringDir
 *                       INOUT BSP_GPIO_DIRECTION_e *penDirect
 * Parameters[out]:      INOUT BSP_GPIO_DIRECTION_e *penDirect
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.13
 **********************************************************/
static ULONG BspGpio_GetGpioDirectByString(IN CHAR *pcStringDir, INOUT BSP_GPIO_DIRECTION_e *penDirect)
{
    if (pcStringDir == NULL || penDirect == NULL)
    {
        return STAT_ERR_INVAILD_PARAM;
    }

    for (int i = 0; i < ARRAY_SIZE(gszDirection); i++)
    {
        if (strcmp(pcStringDir, gszDirection[i]) == 0)
        {
            *penDirect = (BSP_GPIO_DIRECTION_e)i;
            return STAT_SUCCESS;
        }
    }

    return STAT_ERR_INVAILD_PARAM;
}

/**********************************************************
 * Function Name:        BspGpio_GetGpioDirect
 * Description:          获取管脚方向
 * Parameters[in]:       IN UINT32 gpio
 *                       INOUT BSP_GPIO_DIRECTION_e *penDirect
 * Parameters[out]:      INOUT BSP_GPIO_DIRECTION_e *penDirect
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.13
 **********************************************************/
ULONG BspGpio_GetGpioDirect(IN UINT32 gpio, INOUT BSP_GPIO_DIRECTION_e *penDirect)
{
    CHAR buf[64] = {0};
    CHAR szValue[128] = {0};
    ULONG uRet = 0;

    if(penDirect == NULL)
    {
        uRet = STAT_ERR_INVAILD_PARAM;
        return uRet;
    }

	sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio);
    if(access(buf, F_OK) == 0)
    {
        uRet = AppFile_ReadStr(buf, szValue, sizeof(szValue));
        if (uRet != STAT_SUCCESS)
        {
            return uRet;
        }

        uRet = BspGpio_GetGpioDirectByString(szValue, penDirect);
    }

	return uRet;
}

/**********************************************************
 * Function Name:        BspGpio_SetGpioValue
 * Description:          设置管脚电平值
 * Parameters[in]:       IN UINT32 gpio
 *                       IN BSP_GPIO_LEVEL_e enVal
 * Parameters[out]:      None
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.13
 **********************************************************/
ULONG BspGpio_SetGpioValue(IN UINT32 gpio, IN BSP_GPIO_LEVEL_e enVal)
{
    CHAR buf[128] = {0};
    ULONG uRet = STAT_SUCCESS;

    if(enVal >= BSP_GPIO_LEVEL_MAX)
    {
        uRet = STAT_ERR_INVAILD_PARAM;
        return uRet;
    }

	sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio);
    if(access(buf, F_OK) == 0)
    {
        uRet = AppFile_writeInt32(buf, enVal);
    }

	return uRet;
}

/**********************************************************
 * Function Name:        BspGpio_GetGpioValue
 * Description:          获取管脚电平值
 * Parameters[in]:       IN UINT32 gpio
 *                       IINOUT BSP_GPIO_LEVEL_e *enVal
 * Parameters[out]:      INOUT BSP_GPIO_LEVEL_e *enVal
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.13
 **********************************************************/
ULONG BspGpio_GetGpioValue(IN UINT32 gpio, INOUT BSP_GPIO_LEVEL_e *penVal)
{
    CHAR buf[64] = {0};
    SINT32 s32Value = 0;
    ULONG uRet = STAT_SUCCESS;

	sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio);
    if(access(buf, F_OK) == 0)
    {
        uRet = AppFile_ReadInt32(buf, &s32Value);
        if (uRet != STAT_SUCCESS)
        {
            return uRet;
        }

        *penVal = (BSP_GPIO_LEVEL_e)s32Value;
    }

	return uRet;
}

/**********************************************************
 * Function Name:        BspGpio_SetGpioPull
 * Description:          日志打印函数，根据日志级别输出带时间戳的格式化日志
 * Parameters[in]:       IN LOG_LVL_e level
 *                       IN const CHAR* format
 *                       ... - 可变参数列表
 * Parameters[out]:      None
 * ReturnValue:          void - 无返回值
 * Author:               liuke
 * Date:                 2024.05.13
 **********************************************************/
ULONG BspGpio_SetGpioPull(IN UINT32 gpio, IN BOOL pull_enable)
{
    CHAR buf[64] = {0};
    ULONG uRet = STAT_SUCCESS;

	snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/pull_enable", gpio);
	if(access(buf, F_OK) == 0)
	{
        uRet = AppFile_writeInt32(buf, pull_enable);
	}

 	return uRet;
}

/**********************************************************
 * Function Name:        BspGpio_GetGpioPull
 * Description:          日志打印函数，根据日志级别输出带时间戳的格式化日志
 * Parameters[in]:       IN UINT32 gpio
 *                       INOUT BOOL *penPullEnable
 * Parameters[out]:      INOUT BOOL *penPullEnable
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2024.05.13
 **********************************************************/
ULONG BspGpio_GetGpioPull(IN UINT32 gpio, INOUT BOOL *penPullEnable)
{
    CHAR buf[64] = {0};
    SINT32 s32Value = 0;
    ULONG uRet = STAT_SUCCESS;

	snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/pull_enable", gpio);
	if(access(buf, F_OK) == 0)
	{
        uRet = AppFile_ReadInt32(buf, &s32Value);
        if (uRet != STAT_SUCCESS)
        {
            return uRet;
        }

        *penPullEnable = (BOOL)s32Value;
	}

 	return uRet;
}

/**********************************************************
 * Function Name:        BspGpio_SetGpioActiveLow
 * Description:          日志打印函数，根据日志级别输出带时间戳的格式化日志
 * Parameters[in]:       IN LOG_LVL_e level
 *                       IN const CHAR* format
 *                       ... - 可变参数列表
 * Parameters[out]:      None
 * ReturnValue:          void - 无返回值
 * Author:               liuke
 * Date:                 2024.05.13
 **********************************************************/
ULONG BspGpio_SetGpioActiveLow(IN UINT32 gpio, IN BSP_GPIO_LEVEL_e active_low)
{
    CHAR buf[64] = {0};
    ULONG uRet = STAT_SUCCESS;

	snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/active_low", gpio);
	if(access(buf, F_OK) == 0)
	{
        uRet = AppFile_writeInt32(buf, active_low);
	}

	return uRet;
}

/**********************************************************
 * Function Name:        BspGpio_GetGpioActiveLow
 * Description:          日志打印函数，根据日志级别输出带时间戳的格式化日志
 * Parameters[in]:       IN LOG_LVL_e level
 *                       IN const CHAR* format
 *                       ... - 可变参数列表
 * Parameters[out]:      None
 * ReturnValue:          void - 无返回值
 * Author:               liuke
 * Date:                 2024.05.13
 **********************************************************/
ULONG BspGpio_GetGpioActiveLow(IN UINT32 gpio, INOUT BSP_GPIO_LEVEL_e *pcActiveLow)
{
    CHAR buf[64] = {0};
    SINT32 s32Value = 0;
    ULONG uRet = STAT_SUCCESS;

	snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/active_low", gpio);
	if(access(buf, F_OK) == 0)
    {
        uRet = AppFile_ReadInt32(buf, &s32Value);
        if (uRet != STAT_SUCCESS)
	    {
            return uRet;
        }

        *pcActiveLow = (BSP_GPIO_LEVEL_e)s32Value;
	}

	return uRet;
}
